﻿using System;
using SlimDX.DirectInput;

namespace TileGert
{
  /// <summary>
  /// GertMouseInput is a simple mouse input class that uses DirectInput.
  /// Use the ButtonIsPressed and ButtonIsReleased methods to check if a button is pressed / released.
  /// The X, Y and Z properties give you the amount of pixels the mouse cursor has moved since the last update.
  /// The data is not automatically updated so if you want up-to-date data, you
  /// need to call the Update method. For example you can call Update once every frame of your game.
  /// </summary>
  public class GertMouseInput
  {
    private Device<MouseState> _mouse = null;
    private MouseState _state = null;
    private GertGame _game = null;
    
    /// <summary>
    /// Creates a new mouse input.
    /// </summary>
    public GertMouseInput(GertGame game)
    {
      _game = game;
      try
      {
        _mouse = new Device<MouseState>(SystemGuid.Mouse);
        _mouse.Acquire();
      }
      catch (Exception ex)
      {
        _game.Logger.LogLine("DirectInput device for the mouse could not be created: " + ex.Message, 0);
      }
    }
    
    /// <summary>
    /// Lazyly gets the current state of the mouse with exception handling.
    /// </summary>
    /// <returns>The current mouse state or null if an exception occurred.</returns>
    private MouseState GetMouseState()
    {
      if (_state == null)
      {
        try
        {
          _state = _mouse.GetCurrentState();
        }
        catch (Exception ex)
        {
          _game.Logger.LogLine("Mousestate could not be read: " + ex.Message, 1);
          return null;
        }
      }
      return _state;
    }
    
    /// <summary>
    /// Updates the mouse state that is used by the KeyIsPressed and KeyIsReleased methods.
    /// </summary>
    public void Update()
    {
      _state = null;
    }
    
    /// <summary>
    /// Checks if the given key is pressed in the current state.
    /// </summary>
    /// <param name="button">The key to be checked.</param>
    /// <returns>True if the is pressed, else false.</returns>
    public bool ButtonIsPressed(int button)
    {
      MouseState state = GetMouseState();
      if (state != null)
        return state.IsPressed(button);
      else
        return false;
    }
    
    /// <summary>
    /// Checks if the given key is pressed in the current state.
    /// </summary>
    /// <param name="button">The key to be checked.</param>
    /// <returns>True if the is pressed, else false.</returns>
    public bool ButtonIsReleased(int button)
    {
      MouseState state = GetMouseState();
      if (state != null)
        return state.IsReleased(button);
      else
        return false;
    }
    
    /// <summary>
    /// Gets the amount of pixels the mouse cursor has moved in X direction since the last update. Can be negative.
    /// </summary>
    public int X
    {
      get 
      {
        MouseState state = GetMouseState();
        if (state != null)
          return state.X;
        else
          return 0;
      }
    }
    
    /// <summary>
    /// Gets the amount of pixels the mouse cursor has moved in Y direction since the last update. Can be negative.
    /// </summary>
    public int Y
    {
      get 
      {
        MouseState state = GetMouseState();
        if (state != null)
          return state.Y;
        else
          return 0;
      }
    }
    
    /// <summary>
    /// Gets the amount of pixels the mouse cursor has moved in Z(?) direction since the last update. Can be negative.
    /// </summary>
    public int Z
    {
      get 
      {
        MouseState state = GetMouseState();
        if (state != null)
          return state.Z;
        else
          return 0;
      }
    }
    
    /// <summary>
    /// Gets the number of buttons the mouse has.
    /// </summary>
    public int NumberOfButtons
    {
      get { return _mouse.Caps.ButtonCount; }
    }
    
    /// <summary>
    /// Gets the name of the mouse that can be used for display purposes.
    /// </summary>
    public string DisplayName
    {
      get { return _mouse.DeviceInformation.ProductName; }
    }
    
  }
}
